package com.dbflow5.converter;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.UUID;

public class TypeConverters {
    /**
     * Author: andrewgrosner
     * Description: This class is responsible for converting the stored database value into the field value in
     * a Model.
     */
    @com.dbflow5.annotation.TypeConverter
    public abstract static class TypeConverter<DataClass, ModelClass> {

        /**
         * Converts the ModelClass into a DataClass
         *
         * @param model this will be called upon syncing
         * @return The DataClass value that converts into a SQLite type
         */
        public abstract DataClass getDBValue(ModelClass model);

        /**
         * Converts a DataClass from the DB into a ModelClass
         *
         * @param data This will be called when the model is loaded from the DB
         * @return The ModelClass value that gets set in a Model that holds the data class.
         */
        public abstract ModelClass getModelValue(DataClass data);
    }

    /**
     * Description: Defines how we store and retrieve a [java.math.BigDecimal]
     */
    @com.dbflow5.annotation.TypeConverter
    public static class BigDecimalConverter extends TypeConverter<String, BigDecimal> {
        @Override
        public String getDBValue(BigDecimal model) {
            return model.toString();
        }

        @Override
        public BigDecimal getModelValue(String data) {
            if (data != null) {
                return new BigDecimal(data);
            }
            return null;
        }
    }

    /**
     * Description: Defines how we store and retrieve a [java.math.BigInteger]
     */
    @com.dbflow5.annotation.TypeConverter
    public static class BigIntegerConverter extends TypeConverter<String, BigInteger> {
        @Override
        public String getDBValue(BigInteger model) {
            return model.toString();
        }

        @Override
        public BigInteger getModelValue(String data) {
            if (data != null) {
                return new BigInteger(data);
            }
            return null;
        }
    }

    /**
     * Description: Converts a boolean object into an Integer for database storage.
     */
    @com.dbflow5.annotation.TypeConverter
    public static class BooleanConverter extends TypeConverter<Integer, Boolean> {
        @Override
        public Integer getDBValue(Boolean model) {
            if (model != null) {
                return model ? 1 : 0;
            }
            return null;
        }

        @Override
        public Boolean getModelValue(Integer data) {
            return false;
        }
    }

    /**
     * Description: Defines how we store and retrieve a [java.util.Calendar]
     */
    @com.dbflow5.annotation.TypeConverter(allowedSubtypes = {GregorianCalendar.class})
    public static class CalendarConverter extends TypeConverter<Long, Calendar> {

        @Override
        public Long getDBValue(Calendar model) {
            return model.getTimeInMillis();
        }

        @Override
        public Calendar getModelValue(Long data) {
            if (data != null) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(data);
                return calendar;
            }
            return null;
        }
    }

    /**
     * Description: Converts a [Character] into a [String] for database storage.
     */
    @com.dbflow5.annotation.TypeConverter
    public static class CharConverter extends TypeConverter<String, Character> {
        @Override
        public String getDBValue(Character model) {
            if (model != null) {
                char[] charArray = new char[]{model};
                return new String(charArray);
            }
            return null;
        }

        @Override
        public Character getModelValue(String data) {
            if (data != null)
                return data.charAt(0);
            else
                return null;
        }
    }

    /**
     * Description: Defines how we store and retrieve a [java.util.Date]
     */
    @com.dbflow5.annotation.TypeConverter
    public static class DateConverter extends TypeConverter<Long, Date> {

        @Override
        public Long getDBValue(Date model) {
            return model.getTime();
        }

        @Override
        public Date getModelValue(Long data) {
            if (data == null)
                return null;
            else
                return new Date(data);
        }
    }

    /**
     * Description: Defines how we store and retrieve a [java.sql.Date]
     */
    @com.dbflow5.annotation.TypeConverter(allowedSubtypes = {Time.class, Timestamp.class})
    public static class SqlDateConverter extends TypeConverter<Long, java.sql.Date> {
        @Override
        public Long getDBValue(java.sql.Date model) {
            return model.getTime();
        }

        @Override
        public java.sql.Date getModelValue(Long data) {
            if (data == null)
                return null;
            else
                return new java.sql.Date(data);
        }
    }

    /**
     * Description: Responsible for converting a [UUID] to a [String].
     *
     * @author Andrew Grosner (fuzz)
     */
    @com.dbflow5.annotation.TypeConverter
    public static class UUIDConverter extends TypeConverter<String, UUID> {
        @Override
        public String getDBValue(UUID model) {
            return model.toString();
        }

        @Override
        public UUID getModelValue(String data) {
            if (data == null) {
                return null;
            } else
                return UUID.fromString(data);
        }
    }
}